home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / SampleDeviceOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  10.9 KB  |  342 lines  |  [TEXT/KAHL]

  1. /* SampleDeviceOutput.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "SampleDeviceOutput.h"
  31. #include "SampleConsts.h"
  32. #include "ExecuteSynthesis.h"
  33. #include "Memory.h"
  34. #include "SoundOutput.h"
  35. #include "Alert.h"
  36. #include "EventLoop.h"
  37. #include "ClipWarnDialog.h"
  38. #include "SynthProgressWindow.h"
  39. #include "ErrorDaemon.h"
  40.  
  41.  
  42. #define NUMBEROFBUFFERS (8)
  43. #define INITIALNUMBUFFERS (2)
  44.  
  45. #define CANCELCHECKTIMER (50)
  46.  
  47.  
  48. typedef struct
  49.     {
  50.         MyBoolean                            UseStereo;
  51.         long                                    SamplingRate;
  52.         OutputNumBitsType            NumBitsOut;
  53.  
  54.         void*                                    CurrentBuffer;
  55.         long                                    TotalFramesPerBuffer;
  56.         long                                    CurrentBufferIndex;
  57.         long                                    TotalSampleCount;
  58.         long                                    ClippedSampleCount;
  59.         largefixedsigned            MaxClipExtent;
  60.  
  61.         long                                    CancelCheck;
  62.  
  63.         SynthWinRec*                    Window;
  64.     } StateRecord;
  65.  
  66.  
  67. static MyBoolean            CallbackRoutine(StateRecord* Info, largefixedsigned* DataBlock,
  68.                                                 long NumFrames, MyBoolean* AbortPlaybackFlagOut)
  69.     {
  70.         long                                Limit;
  71.         long                                BufferOffset;
  72.         void*                                Buffer;
  73.         long                                Scan;
  74.         largefixedsigned        TempValue;
  75.  
  76.         Info->CancelCheck -= 1;
  77.         if (Info->CancelCheck < 0)
  78.             {
  79.                 Info->CancelCheck = CANCELCHECKTIMER;
  80.                 if (RelinquishCPUJudiciouslyCheckCancel())
  81.                     {
  82.                         *AbortPlaybackFlagOut = True;
  83.                         return True;
  84.                     }
  85.             }
  86.  
  87.         if (NumFrames + Info->CurrentBufferIndex > Info->TotalFramesPerBuffer)
  88.             {
  89.                 /* submit the buffer & get another */
  90.                 SubmitBuffer((char*)Info->CurrentBuffer,Info->CurrentBufferIndex,NIL,NIL);
  91.                 Info->CurrentBuffer = NIL;
  92.                 do
  93.                     {
  94.                         Info->CurrentBuffer = CheckOutSoundBuffer();
  95.                         if (Info->CurrentBuffer == NIL)
  96.                             {
  97.                                 /* spinwait until a buffer is available */
  98.                                 if (RelinquishCPUCheckCancel())
  99.                                     {
  100.                                         *AbortPlaybackFlagOut = True;
  101.                                         return True;
  102.                                     }
  103.                             }
  104.                     } while (Info->CurrentBuffer == NIL);
  105.                 Info->CurrentBufferIndex = 0;
  106.  
  107.                 if (NumFrames + Info->CurrentBufferIndex > Info->TotalFramesPerBuffer)
  108.                     {
  109.                         /* buffer overrun! */
  110.                         AlertHalt("The output buffer space is too small.  Increase the "
  111.                             "number of bytes allocated to sound buffering.",NIL);
  112.                         return False;
  113.                     }
  114.             }
  115.  
  116.         Limit = NumFrames;
  117.         BufferOffset = Info->CurrentBufferIndex;
  118.         if (Info->UseStereo)
  119.             {
  120.                 Limit *= 2; /* twice as many frames for stereo */
  121.                 BufferOffset *= 2;
  122.             }
  123.         if (Info->NumBitsOut == eOutput8Bits)
  124.             {
  125.                 /* conversion to 8-bits */
  126.                 Buffer = (signed char*)(Info->CurrentBuffer) + BufferOffset;
  127.                 for (Scan = 0; Scan < Limit; Scan += 1)
  128.                     {
  129.                         PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  130.                         TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  131.                         if (TempValue > int2largefixed(1) - 1)
  132.                             {
  133.                                 Info->ClippedSampleCount += 1;
  134.                                 if (TempValue > Info->MaxClipExtent)
  135.                                     {
  136.                                         Info->MaxClipExtent = TempValue;
  137.                                     }
  138.                                 TempValue = int2largefixed(1) - 1;
  139.                             }
  140.                         else if (TempValue < - (int2largefixed(1) - 1))
  141.                             {
  142.                                 Info->ClippedSampleCount += 1;
  143.                                 if (- TempValue > Info->MaxClipExtent)
  144.                                     {
  145.                                         Info->MaxClipExtent = - TempValue;
  146.                                     }
  147.                                 TempValue = - (int2largefixed(1) - 1);
  148.                             }
  149.                         PRNGCHK(Info->CurrentBuffer,&(((signed char*)Buffer)[Scan]),
  150.                             sizeof(((signed char*)Buffer)[Scan]));
  151.                         ((signed char*)Buffer)[Scan] = TempValue >> (largefixed_precision - 8 + 1);
  152.                     }
  153.             }
  154.          else
  155.             {
  156.                 /* conversion to 16-bits */
  157.                 Buffer = (signed short*)(Info->CurrentBuffer) + BufferOffset;
  158.                 for (Scan = 0; Scan < Limit; Scan += 1)
  159.                     {
  160.                         PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  161.                         TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  162.                         if (TempValue > int2largefixed(1) - 1)
  163.                             {
  164.                                 Info->ClippedSampleCount += 1;
  165.                                 if (TempValue > Info->MaxClipExtent)
  166.                                     {
  167.                                         Info->MaxClipExtent = TempValue;
  168.                                     }
  169.                                 TempValue = int2largefixed(1) - 1;
  170.                             }
  171.                         else if (TempValue < - (int2largefixed(1) - 1))
  172.                             {
  173.                                 Info->ClippedSampleCount += 1;
  174.                                 if (- TempValue > Info->MaxClipExtent)
  175.                                     {
  176.                                         Info->MaxClipExtent = - TempValue;
  177.                                     }
  178.                                 TempValue = - (int2largefixed(1) - 1);
  179.                             }
  180.                         PRNGCHK(Info->CurrentBuffer,&(((signed short*)Buffer)[Scan]),
  181.                             sizeof(((signed short*)Buffer)[Scan]));
  182.                         ((signed short*)Buffer)[Scan] = TempValue >> (largefixed_precision - 16 + 1);
  183.                     }
  184.             }
  185.         Info->CurrentBufferIndex += NumFrames;
  186.  
  187.         Info->TotalSampleCount += NumFrames;
  188.  
  189.         UpdateSynthWindow(Info->Window,Info->SamplingRate,Info->TotalSampleCount,
  190.             Info->ClippedSampleCount,False);
  191.  
  192.         return True;
  193.     }
  194.  
  195.  
  196. /* this routine opens the sound channel & performs resampling to it. */
  197. void                                    SynthToSoundDevice(struct MainWindowRec* MainWindow,
  198.                                                 struct ArrayRec* ListOfTracks, struct TrackObjectRec* KeyTrack,
  199.                                                 long FrameToStartAt, long SamplingRate, long EnvelopeRate,
  200.                                                 MyBoolean UseStereo, LargeBCDType DefaultBeatsPerMinute,
  201.                                                 LargeBCDType OverallVolumeScalingReciprocal,
  202.                                                 MyBoolean InterpOverTime, MyBoolean InterpAcrossWaves,
  203.                                                 LargeBCDType ScanningGap, OutputNumBitsType NumBitsOut,
  204.                                                 LargeBCDType SecondsOfBuffering, MyBoolean ClipWarn)
  205.     {
  206.         StateRecord                    StateInfo;
  207.         SynthErrorCodes            SynthErrorReturnCode;
  208.         ErrorDaemonRec*            ErrorDaemon;
  209.  
  210.         CheckPtrExistence(MainWindow);
  211.         CheckPtrExistence(ListOfTracks);
  212.         CheckPtrExistence(KeyTrack);
  213.         if (SecondsOfBuffering < Double2LargeBCD(1))
  214.             {
  215.                 SecondsOfBuffering = Double2LargeBCD(1);
  216.             }
  217.         if (SamplingRate < MINSAMPLINGRATE)
  218.             {
  219.                 SamplingRate = MINSAMPLINGRATE;
  220.             }
  221.  
  222.         StateInfo.UseStereo = UseStereo;
  223.         StateInfo.SamplingRate = SamplingRate;
  224.         StateInfo.NumBitsOut = NumBitsOut;
  225.  
  226.         StateInfo.CurrentBuffer = NIL;
  227.         StateInfo.TotalFramesPerBuffer = (LargeBCD2Single(SecondsOfBuffering)
  228.             * SamplingRate) / NUMBEROFBUFFERS;
  229.         StateInfo.CurrentBufferIndex = 0;
  230.         StateInfo.TotalSampleCount = 0;
  231.         StateInfo.ClippedSampleCount = 0;
  232.         StateInfo.MaxClipExtent = 0;
  233.  
  234.         StateInfo.CancelCheck = 0;
  235.  
  236.         StateInfo.Window = NewSynthWindow(EnvelopeRate / 2,True/*show clipping*/);
  237.         if (StateInfo.Window == NIL)
  238.             {
  239.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  240.              SetupFailurePoint1:
  241.                 return;
  242.             }
  243.  
  244.         if (!OpenSoundChannel(SamplingRate,UseStereo ? eStereo : eMono,
  245.             (NumBitsOut == eOutput8Bits) ? e8bit : e16bit,StateInfo.TotalFramesPerBuffer,
  246.             NUMBEROFBUFFERS,INITIALNUMBUFFERS))
  247.             {
  248.                 AlertHalt("Unable to open the sound output device.",NIL);
  249.              SetupFailurePoint2:
  250.                 DisposeSynthWindow(StateInfo.Window);
  251.                 goto SetupFailurePoint1;
  252.             }
  253.  
  254.         StateInfo.CurrentBuffer = CheckOutSoundBuffer();
  255.         if (StateInfo.CurrentBuffer == NIL)
  256.             {
  257.                 /* there should initially be a buffer available */
  258.                 AlertHalt("Unable to access sound buffer.",NIL);
  259.              SetupFailurePoint3:
  260.                 CloseSoundChannel(NIL,NIL);
  261.                 goto SetupFailurePoint2;
  262.             }
  263.  
  264.         ErrorDaemon = NewErrorDaemon();
  265.         if (ErrorDaemon == NIL)
  266.             {
  267.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  268.              SetupFailurePoint4:
  269.                 goto SetupFailurePoint3;
  270.             }
  271.  
  272.         SynthErrorReturnCode = Synthesizer(MainWindow,
  273.             (MyBoolean (*)(void*,largefixedsigned*,long,MyBoolean*))&CallbackRoutine,
  274.             &StateInfo,ListOfTracks,KeyTrack,FrameToStartAt,SamplingRate,EnvelopeRate,
  275.             UseStereo,DefaultBeatsPerMinute,OverallVolumeScalingReciprocal,InterpOverTime,
  276.             InterpAcrossWaves,ScanningGap,ErrorDaemon);
  277.  
  278.         UpdateSynthWindow(StateInfo.Window,StateInfo.SamplingRate,StateInfo.TotalSampleCount,
  279.             StateInfo.ClippedSampleCount,True);
  280.  
  281.         if ((StateInfo.CurrentBuffer != NIL) && (SynthErrorReturnCode == eSynthDone))
  282.             {
  283.                 SubmitBuffer((char*)StateInfo.CurrentBuffer,StateInfo.CurrentBufferIndex,NIL,NIL);
  284.                 StateInfo.CurrentBuffer = NIL;
  285.             }
  286.  
  287.         switch (SynthErrorReturnCode)
  288.             {
  289.                 default:
  290.                     EXECUTE(PRERR(AllowResume,
  291.                         "SynthToSoundDevice:  bad return code from Synthesizer()"));
  292.                     break;
  293.                 case eSynthDone:
  294.                     break;
  295.                 case eSynthNoMemory:
  296.                     AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  297.                     break;
  298.                 case eSynthUserCancelled:
  299.                     break;
  300.                 /* case eSynthProgramError: */
  301.                     break;
  302.                 case eSynthPrereqError:
  303.                     break;
  304.                 case eSynthUndefinedInstrumentError:
  305.                     break;
  306.                 case eSynthDataSubmitError:
  307.                     AlertHalt("An error occurred while sending data to output device.",NIL);
  308.                     break;
  309.                 case eSynthDuplicateNames:
  310.                     break;
  311.             }
  312.  
  313.         if (SynthErrorReturnCode == eSynthUserCancelled)
  314.             {
  315.                 KillSoundChannel(); /* don't wait for buffers to play out */
  316.             }
  317.          else
  318.             {
  319.                 CloseSoundChannel(NIL,NIL);
  320.             }
  321.         DisposeSynthWindow(StateInfo.Window);
  322.  
  323.         if (ErrorDaemonDidClampingOccur(ErrorDaemon))
  324.             {
  325.                 ClampWarnDialog(ErrorDaemonGetMaxClamping(ErrorDaemon),
  326.                     ErrorDaemonGetMaxClamping(ErrorDaemon)
  327.                     * LargeBCD2Double(OverallVolumeScalingReciprocal));
  328.             }
  329.          else
  330.             {
  331.                 if (ClipWarn && (StateInfo.ClippedSampleCount != 0))
  332.                     {
  333.                         ClipWarnDialog(StateInfo.ClippedSampleCount,StateInfo.TotalSampleCount,
  334.                             largefixed2double(StateInfo.MaxClipExtent),
  335.                             largefixed2double(StateInfo.MaxClipExtent)
  336.                             * LargeBCD2Double(OverallVolumeScalingReciprocal),False);
  337.                     }
  338.             }
  339.  
  340.         DisposeErrorDaemon(ErrorDaemon);
  341.     }
  342.